using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Ruminate.Utils;

namespace Ruminate.GUI.Framework {

    /// <summary>
    /// Entry point for the Ruminate GUI library. Servers as a layer of abstraction to 
    /// control what the user is able to interact with.
    /// </summary>
    public class RuminateGUI {

        /*####################################################################*/
        /*                              Variables                             */
        /*####################################################################*/                

        /// <summary>
        /// 
        /// </summary>
        private ElementManager ElementManager { get; set; }                

        /// <summary>
        /// 
        /// </summary>
        internal InstanceData InstanceData { get; set; }
        internal Game Game { get; private set; }

        /*####################################################################*/
        /*                            Initialization                          */
        /*####################################################################*/                

        /// <summary>
        /// 
        /// </summary>
        /// <param name="game"></param>
        public RuminateGUI(Game game) {

            Game = game;

            DebugUtils.Init(Game.GraphicsDevice);

            InputSystem.Initialize(Game.Window);

            InstanceData = new InstanceData {
                //Set game's graphics device
                GraphicsDevice = Game.GraphicsDevice,

                //Set rendering states
                SamplerState = new SamplerState {
                    AddressU = TextureAddressMode.Clamp,
                    AddressV = TextureAddressMode.Clamp,
                    AddressW = TextureAddressMode.Clamp
                },
                RasterizerState = new RasterizerState {
                    CullMode = CullMode.None,
                    ScissorTestEnable = true
                },

                //Set shared sprite batch
                GuiBatch = new SpriteBatch(game.GraphicsDevice),

                //Initialize the default renderer map
                DefaultRenderers = new Dictionary<string, Renderer>()
            };                      

            ElementManager = new ElementManager(InstanceData);

            InstanceData.InputManager = new InputManager(ElementManager.RootElement);
        }

        /*####################################################################*/
        /*                      External Input Management                     */
        /*####################################################################*/                

        #region Input

        public bool HasMouse { get { return !ElementManager.RootElement.Data.IsHover; } }

        public CharEnteredHandler CharEntered {
            get { return ElementManager.CharEntered; }
            set { ElementManager.CharEntered = value; }
        }

        public KeyEventHandler KeyDown {
            get { return ElementManager.KeyDown; }
            set { ElementManager.KeyDown = value; }
        }

        public KeyEventHandler KeyUp {
            get { return ElementManager.KeyUp; }
            set { ElementManager.KeyUp = value; }
        }

        public MouseEventHandler MouseClick {
            get { return ElementManager.MouseClick; }
            set { ElementManager.MouseClick = value; }
        }

        public MouseEventHandler MouseDoubleClick {
            get { return ElementManager.MouseDoubleClick; }
            set { ElementManager.MouseDoubleClick = value; }
        }

        public MouseEventHandler MouseDown {
            get { return ElementManager.MouseDown; }
            set { ElementManager.MouseDown = value; }
        }

        public MouseEventHandler MouseHover {
            get { return ElementManager.MouseHover; }
            set { ElementManager.MouseHover = value; }
        }

        public MouseEventHandler MouseMove {
            get { return ElementManager.MouseMove; }
            set { ElementManager.MouseMove = value; }
        }

        public MouseEventHandler MouseUp {
            get { return ElementManager.MouseUp; }
            set { ElementManager.MouseUp = value; }
        }

        public MouseEventHandler MouseWheel {
            get { return ElementManager.MouseWheel; }
            set { ElementManager.MouseWheel = value; }
        }

        #endregion

        /*####################################################################*/
        /*                        Set Ruminate Settings                       */
        /*####################################################################*/                

        #region Settings

        /// <summary>
        /// 
        /// </summary>
        /// <param name="theme"></param>
        public void SetTheme(Theme theme) {
            InstanceData.DefaultRenderers = theme.ThemeDictionary;
        }

        #endregion

        /*####################################################################*/
        /*                         Add/Remove Elements                        */
        /*####################################################################*/                

        #region Interaction with root element

        /// <summary>
        /// 
        /// </summary>
        /// <param name="element"></param>
        public void AddElement(Element element) {
            ElementManager.AddElement(element);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="element"></param>
        public void RemoveElement(Element element) {
            ElementManager.RemoveElement(element);
        }

        #endregion

        /*####################################################################*/
        /*                           Main Loop Hooks                          */
        /*####################################################################*/                

        #region Logic to be tied into the main game loop

        /// <summary>
        /// Update all active elements
        /// </summary>
        public void Update() {
            ElementManager.UpdateElements();
        }

        /// <summary>
        /// Draw all visible elements
        /// </summary>
        public void Draw() {
            InstanceData.GuiBatch.Begin(
                SpriteSortMode.Immediate, 
                BlendState.AlphaBlend);
            ElementManager.Draw();
            InstanceData.GuiBatch.End();
        }

        #endregion
    }
}
